#include "stdafx.h"
#include "WidgetWin.h"
#include "resource.h"
#include "SkCanvas.h"
#include "LayoutHorizontal.h"
#include "LayoutVertical.h"
#include "View.h"
#include "RootView.h"
#include "FocusManager.h"
#include "MainView.h"
#include "EventManager.h"

WidgetWin& WidgetWin::m_widget = WidgetWin::getInstance();

WidgetWin::WidgetWin()
	: m_wnd(NULL)
	, m_rootView(NULL)
	, m_isCaption(false)
	, m_focusManager(NULL)
	, m_gdiplusToken(0)
{
	m_rootView = new MainView();
	m_focusManager = new FocusManager();
	m_eventManager = new EventManager();

	Gdiplus::GdiplusStartupInput gdiplusStartupInput;

	// Initialize GDI+. 
	Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
}


WidgetWin::~WidgetWin()
{
	delete m_rootView;
	m_rootView = NULL;
	
	delete m_focusManager;
	m_focusManager = NULL;

	delete m_eventManager;
	m_eventManager = NULL;

	delete work_thread_;
	work_thread_ = NULL;

	Gdiplus::GdiplusShutdown(m_gdiplusToken);
}

// LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
bool WidgetWin::createWindow(HINSTANCE hInstance, int nCmdShow)
{
	// Register window class 
	WNDCLASSEX wcex;
	const wchar_t szWindowClass[] = L"UIDemo";
	const wchar_t szTitle[] = L"Simple";

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
	wcex.lpfnWndProc = WidgetWin::WndProc; // WndProc;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = hInstance;
	wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_UIDEMO));
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground = NULL; //  (HBRUSH)(COLOR_WINDOW + 1);
	wcex.lpszMenuName = NULL; // MAKEINTRESOURCE(IDC_UIDEMO);
	wcex.lpszClassName = szWindowClass;
	wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	RegisterClassEx(&wcex);

	// hInst = hInstance; // Store instance handle in our global variable

	m_wnd = ::CreateWindow(szWindowClass, szTitle, 
		WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
		CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL);

	if (!m_wnd)
	{
		return false;
	}

	ShowWindow(m_wnd, nCmdShow);
	UpdateWindow(m_wnd);

	return true;
}

LRESULT WidgetWin::OnWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;
	// return DefWindowProc(hWnd, message, wParam, lParam);

	switch (message)
	{
	case WM_COMMAND:
		wmId = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// Parse the menu selections:
		switch (wmId)
		{
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
	case WM_CREATE:
	{
		CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lParam);
		if (cs==NULL)
		{
			ATLTRACE("create struct error");
			break;
		}

		RECT rcClient;
		if (GetClientRect(hWnd, &rcClient))
		{
			m_width = rcClient.right - rcClient.left;
			m_height = rcClient.bottom - rcClient.top;
		}

		init();
	}
		break;
	case WM_PAINT:
	{
		hdc = BeginPaint(hWnd, &ps);
		// TODO: Add any drawing code here...
		// ATLTRACE("dirty area:(%d, %d, %d, %d)\r\n", ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);
/*
		HDC mem_dc_ = CreateCompatibleDC(hdc);
		HBITMAP h_bitmap_ = CreateCompatibleBitmap(mem_dc_, m_width, m_height);
		// mem_base_bitmap_.reset(new Gdiplus::Bitmap(h_bitmap,));
		SelectObject(mem_dc_, h_bitmap_);
*/

		CRect clientRect;
		GetClientRect(hWnd, &clientRect);
		SkCanvas* canvas = new SkCanvas(hdc, clientRect.Width(), clientRect.Height());
		// if (!canvas_)
		// {
		//	canvas_ = new SkCanvas(hdc, clientRect.Width(), clientRect.Height());
		// }

		if (m_rootView)
		{
			m_rootView->onPaint(canvas);
		}

		canvas->onPaint(hdc);

		// BitBlt(hdc, 0, 0, m_width, m_height, mem_dc_, 0, 0, SRCCOPY);

		EndPaint(hWnd, &ps);

		delete canvas;
	}
	break;
/*
	case WM_ERASEBKGND:
	{
		return 0;
	}
*/
	case WM_DESTROY:
/*
		if (canvas_)
		{
			delete canvas_; // del canvas_ before GdiplusShutdown.
			canvas_ = NULL;
		}
*/
		PostQuitMessage(0);
		break;
	case WM_SIZE:
	{
		m_width = LOWORD(lParam);
		m_height = HIWORD(lParam);

		if (m_rootView)
		{
			m_rootView->setBolder(0, 0, m_width, m_height);
			m_rootView->updateLayout();
		}

		// first WM_SIZE message is for UI ready.
		static bool is_first = true;
		if (is_first)
		{
			work_thread_ = new std::thread(thread_fun, "hahah");
			is_first = false;
		}
	}
	break;
/*
	case WM_ACTIVATE:
		{
			unsigned short status = LOWORD(wParam);
			if (status == WM_ACTIVATE
				|| status == WA_CLICKACTIVE)
			{
				if (!m_isCaption)
				{
					::SetCapture(m_wnd);
					m_isCaption = true;
				}
			}
		}
		break;

*/
	case WM_MOUSEWHEEL:
	{
		short wheel = HIWORD(wParam);
		short xPos = LOWORD(lParam);
		short yPos = HIWORD(lParam);
		if (m_eventManager)
		{
			m_eventManager->onMouseWheel(wheel, xPos, yPos);
		}
	}

		break;
	case WM_MOUSEHWHEEL:
		break;
	case WM_LBUTTONDOWN:
		{
			short xPos = LOWORD(lParam);
			short yPos = HIWORD(lParam);
			ATLTRACE("WM_LBUTTONDOWN:(%d, %d)\r\n", xPos, yPos);

			if (m_focusManager)
			{
				m_focusManager->onLButtonDown(xPos, yPos);
			}

			if (m_eventManager)
			{
				m_eventManager->onLButtonDown(xPos, yPos);
			}
		}
		break;
	case WM_LBUTTONDBLCLK:
	{
		short xPos = LOWORD(lParam);
		short yPos = HIWORD(lParam);
		ATLTRACE("WM_LBUTTONDOWN:(%d, %d)\r\n", xPos, yPos);

		if (m_focusManager)
		{
			m_focusManager->onLButtonDown(xPos, yPos);
		}

		if (m_eventManager)
		{
			m_eventManager->onLButtonDBClick(xPos, yPos);
		}
	}
	break;
	case WM_LBUTTONUP:
		{
			short xPos = LOWORD(lParam);
			short yPos = HIWORD(lParam);
			ATLTRACE("WM_LBUTTONUP:(%d, %d)\r\n", xPos, yPos);

			if (m_focusManager)
			{
				m_focusManager->onLButtonUp(xPos, yPos);
			}
			if (m_eventManager)
			{
				m_eventManager->onLButtonUp(xPos, yPos);
			}

		}
		break;

	case WM_MOUSEMOVE:
	{
		short xPos = LOWORD(lParam);
		short yPos = HIWORD(lParam);
		// ATLTRACE("mouse move:(%d, %d)\r\n", xPos, yPos);

		if (m_focusManager)
		{
			m_focusManager->onMouseMove(xPos, yPos);
		}
		if (m_eventManager)
		{
			m_eventManager->onMouseMove(xPos, yPos);
		}


#if 0
		RECT reClient;
		GetClientRect(m_wnd, &reClient);
		if (reClient.left < xPos && xPos < reClient.right + 1
			&& reClient.top < yPos && yPos < reClient.bottom + 1)
		{
			if (!m_isCaption)
			{
				::SetCapture(m_wnd);
				m_isCaption = true;
			}
		}
		else
		{
			if (m_isCaption)
			{
				if (MK_LBUTTON != wParam)
				{
					::ReleaseCapture();
					m_isCaption = false;
				}
			}
		}
#endif // 0

	}
		break;
	case WM_CHAR:
	{ // WM_IME_STARTCOMPOSITION,WM_IME_COMPOSITION,WM_IME_ENDCOMPOSITION
		ATLTRACE(L"[0x%02X][%c]\r\n", static_cast<uint32>(wParam), static_cast<WCHAR>(wParam));

		if (m_eventManager)
		{
			m_eventManager->onChar(static_cast<uint32>(wParam));
		}
	}
	break;
	case WM_KEYDOWN:
		{ // WM_IME_STARTCOMPOSITION,WM_IME_COMPOSITION,WM_IME_ENDCOMPOSITION
			ATLTRACE(L"[0x%02X][%c]\r\n", static_cast<uint32>(wParam), static_cast<WCHAR>(wParam));

			if (m_eventManager)
			{
				m_eventManager->onKeyDown(static_cast<uint32>(wParam));
			}
		}
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}

	return DefWindowProc(hWnd, message, wParam, lParam);
}

LRESULT CALLBACK WidgetWin::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{

	return m_widget.OnWndProc(hWnd, message, wParam, lParam);

}

bool WidgetWin::init()
{
	if (m_rootView==NULL)
	{
		return false;
	}

	if (!m_rootView->init())
	{
		return false;
	}

	m_rootView->setBolder(0, 0, m_width, m_height);
	m_rootView->updateLayout();
	return true;
}

bool WidgetWin::deinit()
{
	if (m_rootView == NULL)
	{
		return false;
	}

	work_thread_->join();

	return m_rootView->deinit();
}